package com.game;

import com.young.R;

import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class PuzzleView extends SurfaceView implements Runnable, SurfaceHolder.Callback {
	
	private static final String TAG = PuzzleView.class.getSimpleName();
	
	private OnButtonClickListener mOnButtonClickListener;
	
	private Context context = null;
	public static int screenW = 0;
	public static int screenH = 0;
	
	private Thread gameThd = null;
	private SurfaceHolder sfh = null;
	private Canvas canvas = null;
	private Paint paint = null;
	private ColorMatrix colorMatrix = null;
	private ColorMatrixColorFilter colorMatrixFilter = null;
	private boolean threadFlag = true;
	
	private Bitmap template = null;
	private Bitmap pause = null;
	private Bitmap background = null;
	private Bitmap win = null;
	private Bitmap lose = null;
	
	private Bitmap winlight = null;
	private Bitmap win1 = null, win2 = null, win3 = null;
	private Bitmap loselight = null;
	private Bitmap lose1 = null, lose2 = null, lose3 = null;
	private int frameId = 0;
	
	private Rect pauseLocation = null;
	private RectF templateLocation = null;
	private PuzzlePathArea pathArea = null;
	
	private PuzzlePathManager puzzlePathManager = null;
	private PuzzleUtil focusPuzzleUtil = null;
	
	private TimeManager timeManager = null;
	
	private static final int GAME_LOSE = -1;
	private static final int GAME_START = 0;
	private static final int GAME_PAUSE = 1;
	private static final int GAME_WIN = 2;
	private int gameState = GAME_START;
	
	private float touchDownX = 0;
	private  float touchDownY = 0;
	private float lastEventX = 0;
	private float lastEventY = 0;
	private float curEventX = 0;
	private float curEventY = 0;
	private int eventType = -1;
	private boolean touchEventFlag = true;
	
	private int bigStage = 0;
	private int smallStage = 0;
	
	public PuzzleView(Context context) {
		super(context);
	
		this.context = context;
		
		sfh = this.getHolder();
		sfh.addCallback(this);
		
		paint = new Paint();
		paint.setAntiAlias(true);
		paint.setFilterBitmap(true);
		paint.setStyle(Style.STROKE);
		paint.setColor(Color.BLUE);
		
		colorMatrix = new ColorMatrix();
		colorMatrix.setSaturation(0);

//		colorMatrix.set(new float[]{1.0f, 0.0f, 0.0f, 0, 0,  
//									0.0f, 2.0f, 0.0f, 0, 0,  
//									0.0f, 0.0f, 1.0f, 0, 0,  
//									0,      0,     0, 1, 0});
		colorMatrixFilter = new ColorMatrixColorFilter(colorMatrix);

		paint.setStrokeWidth(3);
		setFocusable(true);
		
		template = BitmapFactory.decodeResource(this.getResources(), Stage.stageId[bigStage][smallStage]);
		background = BitmapFactory.decodeResource(this.getResources(), R.drawable.bg_background);
		win = BitmapFactory.decodeResource(this.getResources(), R.drawable.img_win);
		lose = BitmapFactory.decodeResource(this.getResources(), R.drawable.img_lose);
		pause = BitmapFactory.decodeResource(this.getResources(), R.drawable.btn_pause);
		pauseLocation = new Rect(0, 0, pause.getWidth(), pause.getHeight()); 
		
		Options opts = new Options();
		opts.inSampleSize = 2;
		winlight = BitmapFactory.decodeResource(this.getResources(), R.drawable.img_winlight, opts);
		win1 = BitmapFactory.decodeResource(this.getResources(), R.drawable.img_win1, opts);
		win2 = BitmapFactory.decodeResource(this.getResources(), R.drawable.img_win2, opts);
		win3 = BitmapFactory.decodeResource(this.getResources(), R.drawable.img_win3, opts);
		
		loselight = BitmapFactory.decodeResource(this.getResources(), R.drawable.img_loselight, opts);
		lose1 = BitmapFactory.decodeResource(this.getResources(), R.drawable.img_lose1, opts);
		lose2 = BitmapFactory.decodeResource(this.getResources(), R.drawable.img_lose2, opts);
		lose3 = BitmapFactory.decodeResource(this.getResources(), R.drawable.img_lose3, opts);
			
		puzzlePathManager = new PuzzlePathManager();
		timeManager = new TimeManager(getContext());
		//timeManager.loadBmp();
	}
	
	public void setStage(int bigstage, int smallstage) {
		bigStage = bigstage;
		smallStage = smallstage;
	}
	
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
		Log.v(TAG, "surfaceView Changed");
	}
	
	public void surfaceCreated(SurfaceHolder holder) {
		Log.v(TAG, "surfaceView Create");
		screenW = this.getWidth();
		screenH = this.getHeight();
		
		if (pause.getWidth() > screenW / 9) {
			pauseLocation.right = screenW / 9;
			pauseLocation.bottom = pause.getHeight() * (pauseLocation.width() / pause.getWidth());
		}
		
		templateLocation = new RectF(0, screenH / 6, screenH * 5 / 6, screenH);	
		pathArea = new PuzzlePathArea(templateLocation.right,templateLocation.top, screenW, screenH);
		
		if (gameState == GAME_START) {
			puzzlePathManager.createTemplatePath(templateLocation.left, templateLocation.top, 
												 templateLocation.width(), templateLocation.height(),
					                             Stage.stageRow[smallStage], Stage.stageColoum[smallStage]);
			boolean rotate = false;
			if (bigStage >= Stage.STAGE_MODE_ROTATE) {
				rotate = true;
			}
			puzzlePathManager.createPathList(pathArea, rotate);
			
			timeManager.setShowArea(screenW / 10, pauseLocation.height() / 3, screenW * 9 / 10, pauseLocation.height() * 2 / 3);
			if (bigStage == Stage.STAGE_MODE_TIME) {				
				timeManager.startTimer(Stage.stageTime[smallStage], 1);
			}
		}
		else if (gameState == GAME_PAUSE) {
			timeManager.restartTimer();
			gameState = GAME_START;
		}
		
		gameThd = new Thread(this);
		gameThd.start();
		threadFlag = true;
	}
	
	public void surfaceDestroyed(SurfaceHolder holder) {
		Log.v(TAG, "surfaceView Destroyed");
		gameState = GAME_PAUSE;
		timeManager.pauseTimer();
		threadFlag = false;	
	}
	
	public void run() {
		while (threadFlag) {
			long startTime =  System.currentTimeMillis();
			game_Draw();
			game_Logic();
			long endTime = System.currentTimeMillis();
			Log.v(TAG, "Time Cost: " + (endTime - startTime));
			try {
				if ((endTime - startTime) < 50) {
					Thread.sleep(50 - (endTime - startTime));
				}
			}catch (Exception e) {
					e.printStackTrace();
			}
		}
	}
	
	public void setOnButtonClickListener(OnButtonClickListener listener) {
		mOnButtonClickListener = listener;
	}
	
	private boolean isClick(float x1, float y1, float x2, float y2, float offset) {
		if (offset < 0) {
			offset = -offset;
		}
		if ((Math.abs(x1 - x2) < offset) && (Math.abs(y1 - y2) < offset)) {
			return true;
		}
	
		return false;
	}
	
	private void gameStartTouchEventLogic() {
		switch (eventType) {
		case MotionEvent.ACTION_DOWN:
			Log.v(TAG, "ACTION DOWN");
			if ((pauseLocation.left <= curEventX && curEventX <= pauseLocation.right)
					&& (pauseLocation.top <= curEventY && curEventY <= pauseLocation.bottom)) {
				if (gameState == GAME_START) {
					mOnButtonClickListener.onPause();
				}
			} else {
				focusPuzzleUtil = puzzlePathManager.getFocusUtil(curEventX,
						curEventY);
				if (focusPuzzleUtil != null) {
					touchDownX = curEventX;
					touchDownY = curEventY;
					lastEventX = curEventX;
					lastEventY = curEventY;
					Log.v(TAG, "util select");
				}
			}
			touchEventFlag = true;
			break;
		case MotionEvent.ACTION_MOVE:
			Log.v(TAG, "ACTION MOVE");
			if (focusPuzzleUtil != null) {
				float offsetX = curEventX - lastEventX;
				float offsetY = curEventY - lastEventY;
				Log.v(TAG, "offsetX " + offsetX + " offsetY " + offsetY);
				if ((offsetX < 0 && (focusPuzzleUtil.getLeft() + offsetX < puzzlePathManager
						.getTgetTemplatePathLeft()))
						|| (offsetX > 0 && (focusPuzzleUtil.getRight()
								+ offsetX > screenW))) {
					offsetX = 0;
				}
				if ((offsetY < 0 && (focusPuzzleUtil.getTop() + offsetY < puzzlePathManager
						.getTgetTemplatePathTop()))
						|| (offsetY > 0 && (focusPuzzleUtil.getBottom()
								+ offsetY > screenH))) {
					offsetY = 0;
				}
				focusPuzzleUtil.setOffset(offsetX, offsetY);
				lastEventX = curEventX;
				lastEventY = curEventY;
			}
			break;
		case MotionEvent.ACTION_UP:
			if (focusPuzzleUtil != null
					&& isClick(touchDownX, touchDownY, curEventX, curEventY,
							3.0f)) {
				if (bigStage != Stage.STAGE_MODE_NORMAL) {
					puzzlePathManager.rotateFocusPath();
				}
			} else {
				puzzlePathManager.autoAttach(10.0f);
			}
			puzzlePathManager.cleanFocusUtil();

			touchDownX = touchDownY = 0;
			lastEventX = lastEventY = 0;
			curEventX = curEventY = 0;
			eventType = -1;
			focusPuzzleUtil = null;
			touchEventFlag = true;
			break;
		default:
			break;
		}
	}
	
	private void gameLoseTouchEvent() {
		switch (eventType) {
		case MotionEvent.ACTION_DOWN:
			puzzlePathManager.clearTemplatePath();
			puzzlePathManager.clearPathList();
			puzzlePathManager.createTemplatePath(templateLocation.left, templateLocation.top, 
					 							 templateLocation.width(), templateLocation.height(),
					 							 Stage.stageRow[smallStage], Stage.stageColoum[smallStage]);
			boolean rotate = false;
			if (bigStage >= Stage.STAGE_MODE_ROTATE) {
				rotate = true;
			}
			puzzlePathManager.createPathList(pathArea, rotate);
			
			gameState = GAME_START;
			if (bigStage == Stage.STAGE_MODE_TIME) {				
				timeManager.startTimer(Stage.stageTime[smallStage], 1);
			}
			actionInit();
			break;
		case MotionEvent.ACTION_MOVE:
			break;
		case MotionEvent.ACTION_UP:
			break;
		default:
			break;
		}
	}
	
	private boolean updateStage() {
		SharedPreferences sp = context.getSharedPreferences("gameRecord", Context.MODE_PRIVATE);
		switch (bigStage) {
		case 0:
			sp.edit().putInt("modeone", smallStage).commit();
			break;
		case 1:
			sp.edit().putInt("modetwo", smallStage).commit();
			break;
		case 2:
			sp.edit().putInt("modethree", smallStage).commit();
			break;
		case 3:
			sp.edit().putInt("modefour", smallStage).commit();
			break;
		default:
			break;
		}
		
	    smallStage = (++smallStage) % Stage.SMALL_STAGE_MAX;
	    Log.v(TAG, "smallStage " + smallStage);
	    if (smallStage == 0) {
	    	Log.v(TAG, "click on mainMenu");
	    	mOnButtonClickListener.onMainMenu();
	    	return true;
	    }
	    
	    return false;
	}
	
	private void gameWinTouchEvent() {
		Log.v(TAG, "Win touch event" );
		switch (eventType) {
		case MotionEvent.ACTION_DOWN:
			Log.v(TAG, "Win touch down event" );
			template.recycle();		
			puzzlePathManager.clearTemplatePath();
			puzzlePathManager.clearPathList();
			
			if (!updateStage()) {
				template = BitmapFactory.decodeResource(this.getResources(), Stage.stageId[bigStage][smallStage]);
				puzzlePathManager.createTemplatePath(templateLocation.left, templateLocation.top, 
						 							 templateLocation.width(), templateLocation.height(),
						 							 Stage.stageRow[smallStage], Stage.stageColoum[smallStage]);
				boolean rotate = false;
				if (bigStage >= Stage.STAGE_MODE_ROTATE) {
					rotate = true;
				}
				puzzlePathManager.createPathList(pathArea, rotate);
			
				gameState = GAME_START;
				if (bigStage == Stage.STAGE_MODE_TIME) {					
					timeManager.startTimer(Stage.stageTime[smallStage], 1);
				}
			}
			actionInit();
			break;
		case MotionEvent.ACTION_MOVE:
			break;
		case MotionEvent.ACTION_UP:
			break;
		default:
			break;
		}
	}
	
	public void puzzlePause() {
		timeManager.pauseTimer();
		gameState = GAME_PAUSE;
	}
	
	public void puzzleResume() {
		timeManager.restartTimer();
		gameState = GAME_START;
		Log.v(TAG, "resume gameState " + gameState);
	}
	
	private void game_Logic() {
		Log.v(TAG, "current gameStart " + gameState);
		if (gameState == GAME_START) {
			
			gameStartTouchEventLogic();
			if (puzzlePathManager.puzzleComplete(0.0f)) {
				gameState = GAME_WIN;
				timeManager.pauseTimer();
			}
			else if (bigStage == Stage.STAGE_MODE_TIME &&
					 timeManager.TimerOver()) {
				gameState = GAME_LOSE;
			}
		}
		else if (gameState == GAME_PAUSE) {
			timeManager.pauseTimer();
		}
		else if (gameState == GAME_LOSE) {
			gameLoseTouchEvent();
			actionUpdate();
		}
		else if (gameState == GAME_WIN) {
			gameWinTouchEvent();
			actionUpdate();
		}
	}
	
	private void drawPath(Canvas canvas, Paint paint) {
		//画模版path
		if (bigStage < Stage.STAGE_MODE_NOPIC) {			
			paint.setColor(Color.BLUE);
			paint.setColorFilter(colorMatrixFilter);
			puzzlePathManager.drawTemplatePath(template, canvas, paint);
			paint.setColorFilter(null);
		}
		//画可移动path
		paint.setColor(Color.RED);
		if (gameState == GAME_WIN) {
			puzzlePathManager.drawPath(template, canvas, paint, false);
		}
		else {
			puzzlePathManager.drawPath(template, canvas, paint, true);
		}
		
		//puzzlePathManager.printLayer()
		
	}
	
	private void game_Draw() {
		Log.v(TAG, "run in draw");
		try {
			canvas = sfh.lockCanvas();
			if(canvas != null) {	
			
				//canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));  
				//canvas.drawRGB(0, 0, 0);
				paint.setColor(Color.BLACK);	
				paint.setStyle(Style.STROKE);
				
				canvas.drawBitmap(background, null, new Rect(0, 0, screenW, screenH), paint);
				canvas.drawBitmap(pause, null, pauseLocation, paint);
				timeManager.drawTime(canvas, paint);
				drawPath(canvas, paint);
				paint.setStyle(Style.FILL);
				if (gameState == GAME_WIN) {
					paint.setARGB(128, 128, 128, 128);
					canvas.drawRect(0,  0, screenW, screenH, paint);
					paint.setColor(Color.BLACK);
					drawAction(canvas, paint);
					//canvas.drawBitmap(win, (screenW - win.getWidth()) / 2, 
					//					   (screenH - win.getHeight()) / 2, paint);
				}
				else if (gameState == GAME_LOSE) {
					paint.setARGB(128, 128, 128, 128);
					//paint.setColor(Color.BLACK);
					canvas.drawRect(0,  0, screenW, screenH, paint);
					paint.setColor(Color.BLACK);
					drawAction(canvas, paint);
					//canvas.drawBitmap(lose, (screenW - lose.getWidth()) / 2, 
					//		   				(screenH - lose.getHeight()) / 2, paint);
				}
				
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(canvas != null) {
				sfh.unlockCanvasAndPost(canvas);
				canvas = null;
			}		
		}
	}
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			touchEventFlag = false;
			curEventX = event.getX();
			curEventY = event.getY();
			eventType = event.getAction();
			break;
		case MotionEvent.ACTION_MOVE:
			if (touchEventFlag) {
				curEventX = event.getX();
				curEventY = event.getY();
				eventType = event.getAction();
			}
			break;
		case MotionEvent.ACTION_UP: 
			curEventX = event.getX();
			curEventY = event.getY();
			eventType = event.getAction();
			touchEventFlag = true;
			break;
		default:
			break;
		}
		
		return true;
	}
	
	public interface OnButtonClickListener {
		public void onPause();
		public void onMainMenu();
	}
	
	
	
	public void recycleAll() {
		timeManager.recycle();
		
		template.recycle();
		template = null;
		
		background.recycle();
		background = null;
		
		pause.recycle();
		pause = null;
		
		win.recycle();
		win = null;
		
		lose.recycle();
		lose = null;
	}
	
	private void actionUpdate() {
		frameId++;
	}
	
	private void actionInit() {
		frameId = 0;
	}
	
	private void drawAction(Canvas canvas, Paint paint) {
		Bitmap gameResultLight = null;
		Bitmap gameResultFrame1 = null;
		Bitmap gameResultFrame2 = null;
		Bitmap gameResultFrame3 = null;
		
		if (gameState == GAME_LOSE) {
			gameResultLight = loselight;
			gameResultFrame1 = lose1;
			gameResultFrame2 = lose2;
			gameResultFrame3 = lose3;
		}
		else if(gameState == GAME_WIN) {
			gameResultLight = winlight;
			gameResultFrame1 = win1;
			gameResultFrame2 = win2;
			gameResultFrame3 = win3;
		}
		
		float x = (screenW - gameResultLight.getWidth()) / 2;
		float y = (screenH - gameResultLight.getHeight()) / 2;
		canvas.save();
		canvas.rotate(-(15 * frameId) % 360, screenW / 2, screenH / 2);
		canvas.drawBitmap(gameResultLight, x, y, paint);
		canvas.restore();
		
		x = (screenW - gameResultFrame1.getWidth()) / 2;
		y = (screenH - gameResultFrame1.getHeight()) / 2;
		if (frameId % 4 == 0) {
			canvas.drawBitmap(gameResultFrame1, x, y, paint);
		}
		if (frameId % 4== 1  || frameId % 4== 3) {
			canvas.drawBitmap(gameResultFrame2, x, y, paint);
		}
		if (frameId % 4 == 2) {
			canvas.drawBitmap(gameResultFrame3, x, y, paint);
		}
	}
}
	